package com.siberhus.tools.db2jobj;

import static com.siberhus.commons.lang.NamingConvention.db2java;
import static com.siberhus.commons.lang.NamingConvention.firstUpperCase;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.siberhus.commons.db.Database;

public class Table2JavaConverter {
	
	
	public static final short STYLE_PLAIN = 0;
	public static final short STYLE_JPA = 1;
	
	public static final short MODIFIER_DEFAULT = 0;
	public static final short MODIFIER_PRIVATE = 1;
	public static final short MODIFIER_PROTECTED = 2;
	public static final short MODIFIER_PUBLIC = 3;
	
	private short beanStyle = STYLE_PLAIN;
	private boolean qualifiedTypeName = false;
	
	private short typeAccessModifier = MODIFIER_PRIVATE;
	private short methodAccessModifier = MODIFIER_PUBLIC;
	
	private boolean doOnce = false;

	public Table2JavaConverter(){

	}
	
	public String generate(Connection conn, String tableName) throws SQLException{
		
		tableName = StringUtils.upperCase(tableName);
		
//		StringUtils.substringBeforeLast(arg0, arg1)
		Map<String, String> javaImportMap = new HashMap<String, String>();
		String javaImportPart = "\n\n";
		String javaAttributePart = "";
		String javaMethodPart = "";
		String javaClass = "";
		
		String sql = "select * from "+tableName;		
		PreparedStatement ps = conn.prepareStatement(sql);
		ResultSetMetaData rsmd = ps.executeQuery().getMetaData();
		
		for(int i=1;i<=rsmd.getColumnCount();i++){
			String columnClass = rsmd.getColumnClassName(i);
			String columnName = rsmd.getColumnName(i);
			String attributeName = db2java(columnName);
			
			if(!qualifiedTypeName){
				
				if(columnClass.indexOf("java.lang")==-1){
					/* If it's not in java.lang.* */
					if(!javaImportMap.containsKey(columnClass)){
						javaImportMap.put(columnClass, null);
						/* If it haven't imported class yet */
						javaImportPart+="import "+columnClass+";\n";
					}
				}
				
				columnClass = StringUtils.substringAfterLast(columnClass, ".");
				
			}
			
			
			if(beanStyle==STYLE_JPA){
				
				if(doOnce==false){
					javaImportPart+="import javax.persistence.Column;\n"
						+"import javax.persistence.Entity;\n"
						+"import javax.persistence.GeneratedValue;\n"
						+"import javax.persistence.GenerationType;\n"
						+"import javax.persistence.Id;\n"
						+"import javax.persistence.SequenceGenerator;\n"
						+"import javax.persistence.Table;\n";
					
					javaAttributePart+="\t@SequenceGenerator(name = \""
						+tableName+"_SEQ\",sequenceName = \""
						+tableName+"_SEQ\", initialValue = 1, allocationSize = 1)\n";
					
					javaAttributePart+= "\t@Id\n"
						+"\t@GeneratedValue(strategy = GenerationType.SEQUENCE, generator =\"" 
				    	+tableName+"_SEQ\")\n";
				    
					doOnce = true;
				}
				
				javaAttributePart+="\t@Column(name=\""+columnName+"\")\n";
			}
			
			/* Attribute */
			
			javaAttributePart+="\t";
			switch(typeAccessModifier){
			case MODIFIER_PRIVATE :
				javaAttributePart+="private ";
				break;
			case MODIFIER_PROTECTED :
				javaAttributePart+="protected ";
				break;
			case MODIFIER_PUBLIC :
				javaAttributePart+="public ";
			default:
				javaAttributePart+=" ";
			}
			
			javaAttributePart+=columnClass+" "+attributeName+";\n\n";
			
			
			/* Getter method */
			javaMethodPart+="\tpublic "+columnClass
			+" get"+firstUpperCase(attributeName)
			+"(){\n\t\treturn "+attributeName+";\n\t}\n\n";
			
			/* Setter method */
			javaMethodPart+="\t";
			switch(methodAccessModifier){
			case MODIFIER_PRIVATE :
				javaMethodPart+="private ";
				break;
			case MODIFIER_PROTECTED :
				javaMethodPart+="protected ";
				break;
			case MODIFIER_PUBLIC :
				javaMethodPart+="public ";
				break;
			default:
				javaMethodPart+=" ";
			}
			javaMethodPart+="void set"
			+firstUpperCase(attributeName)
			+"("+columnClass+" "
			+attributeName+"){\n\t\tthis."
			+attributeName+"="
			+attributeName+";\n\t}\n\n";
		}
		
		/* Compose java class from each part */
		javaClass+=javaImportPart.toString()+"\n\n";
		if(beanStyle==STYLE_JPA){
			javaClass+="@Entity\n"+"@Table(name=\""+tableName+"\")\n";
		}
		javaClass+="public class "+firstUpperCase(db2java(tableName))
			+" {\n\n"+javaAttributePart.toString()+"\n\n"
			+javaMethodPart.toString()+"}\n";
		return javaClass.toString();
	}
	
	public void setBeanStyle(short beanStyle) {
		this.beanStyle = beanStyle;
	}

	public boolean isQualifiedTypeName() {
		return qualifiedTypeName;
	}

	public void setQualifiedTypeName(boolean qualifiedTypeName) {
		this.qualifiedTypeName = qualifiedTypeName;
	}
	
	
	public void setMethodAccessModifier(short methodAccessModifier) {
		this.methodAccessModifier = methodAccessModifier;
	}

	public void setTypeAccessModifier(short typeAccessModifier) {
		this.typeAccessModifier = typeAccessModifier;
	}
	
	public static void main(String[] args) throws Exception {
		
		Table2JavaConverter t2o = new Table2JavaConverter();
		t2o.setBeanStyle(Table2JavaConverter.STYLE_JPA);
		Database.ORACLE11.loadDriver();
//		Connection conn = DriverManager.getConnection(Database.ORACLE11.getUrl("loyaltydb",1521,"SCG"), "scg", "blp");
		Connection conn = DriverManager.getConnection(Database.ORACLE11.getUrl("localhost",1521,""), "scg", "blp");
		System.out.println(t2o.generate(conn,"BRAND"));
		
	}
}
